<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>聊天室 - Socket通信系统</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Microsoft YaHei', Arial, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            padding: 20px;
            overflow: hidden;
        }

        .container {
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            border-radius: 15px;
            box-shadow: 0 10px 30px rgba(0,0,0,0.3);
            overflow: hidden;
            display: grid;
            grid-template-columns: 300px 1fr;
            height: calc(100vh - 40px);
        }

        .sidebar {
            background: #2c3e50;
            color: white;
            padding: 20px;
            display: flex;
            flex-direction: column;
            overflow: hidden;
        }

        .sidebar-header {
            text-align: center;
            margin-bottom: 20px;
            padding-bottom: 20px;
            border-bottom: 1px solid #34495e;
            flex-shrink: 0;
        }

        .user-list {
            flex: 1;
            overflow-y: auto;
            margin-bottom: 20px;
            background: #2c3e50;
            border-radius: 8px;
            padding: 10px;
        }

        .user-list::-webkit-scrollbar {
            width: 6px;
        }

        .user-list::-webkit-scrollbar-track {
            background: #34495e;
            border-radius: 3px;
        }

        .user-list::-webkit-scrollbar-thumb {
            background: #3498db;
            border-radius: 3px;
        }

        .user-item {
            padding: 10px;
            margin: 5px 0;
            background: #34495e;
            border-radius: 5px;
            display: flex;
            align-items: center;
            gap: 10px;
            transition: all 0.3s ease;
            border-left: 3px solid transparent;
        }

        .user-item:hover {
            background: #3c556e;
            transform: translateX(2px);
        }

        .user-item.current-user {
            background: #2c3e50;
            border-left: 3px solid #27ae60;
        }

        .user-avatar {
            width: 32px;
            height: 32px;
            background: linear-gradient(135deg, #3498db, #2980b9);
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            color: white;
            flex-shrink: 0;
            font-size: 14px;
        }

        .user-name {
            flex: 1;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            font-size: 13px;
        }

        .user-status {
            font-size: 10px;
            color: #27ae60;
            font-weight: bold;
        }

        .empty-state {
            text-align: center;
            color: #7f8c8d;
            padding: 20px;
            font-style: italic;
            font-size: 13px;
        }

        .main-content {
            display: flex;
            flex-direction: column;
            overflow: hidden;
        }

        .header {
            background: #3498db;
            color: white;
            padding: 20px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            flex-shrink: 0;
        }

        .status {
            display: inline-block;
            padding: 5px 15px;
            border-radius: 20px;
            font-size: 14px;
            font-weight: bold;
        }

        .status.connected {
            background: #27ae60;
        }

        .status.disconnected {
            background: #e74c3c;
        }

        .chat-area {
            flex: 1;
            overflow-y: auto;
            padding: 20px;
            background: #f8f9fa;
            display: flex;
            flex-direction: column;
        }

        .chat-area::-webkit-scrollbar {
            width: 8px;
        }

        .chat-area::-webkit-scrollbar-track {
            background: #e9ecef;
            border-radius: 4px;
        }

        .chat-area::-webkit-scrollbar-thumb {
            background: #3498db;
            border-radius: 4px;
        }

        .chat-area::-webkit-scrollbar-thumb:hover {
            background: #2980b9;
        }

        .message {
            margin-bottom: 15px;
            padding: 12px 15px;
            border-radius: 10px;
            max-width: 80%;
            word-wrap: break-word;
            animation: fadeIn 0.3s ease;
            position: relative;
        }

        @keyframes fadeIn {
            from {
                opacity: 0;
                transform: translateY(10px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }

        .message.system {
            background: #ecf0f1;
            color: #7f8c8d;
            text-align: center;
            margin: 10px auto;
            font-style: italic;
            max-width: 90%;
            border-left: 4px solid #bdc3c7;
        }

        .message.user {
            background: #3498db;
            color: white;
            margin-left: auto;
            border-bottom-right-radius: 3px;
        }

        .message.other {
            background: #e74c3c;
            color: white;
            border-bottom-left-radius: 3px;
        }

        .message-info {
            font-size: 12px;
            opacity: 0.9;
            margin-bottom: 5px;
            font-weight: bold;
        }

        .message-content {
            line-height: 1.4;
            margin-bottom: 5px;
        }

        .timestamp {
            font-size: 11px;
            opacity: 0.7;
            text-align: right;
        }

        .message.user .timestamp {
            color: rgba(255, 255, 255, 0.8);
        }

        .message.other .timestamp {
            color: rgba(255, 255, 255, 0.8);
        }

        .input-area {
            padding: 20px;
            background: white;
            border-top: 1px solid #dee2e6;
            display: flex;
            gap: 10px;
            flex-shrink: 0;
        }

        .message-input {
            flex: 1;
            padding: 12px;
            border: 1px solid #ddd;
            border-radius: 5px;
            font-size: 14px;
            resize: none;
            height: 60px;
            font-family: inherit;
            transition: border-color 0.3s;
        }

        .message-input:focus {
            outline: none;
            border-color: #3498db;
            box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2);
        }

        .send-btn {
            background: #27ae60;
            color: white;
            border: none;
            border-radius: 5px;
            padding: 0 25px;
            cursor: pointer;
            font-size: 14px;
            font-family: inherit;
            transition: background 0.3s;
            flex-shrink: 0;
        }

        .send-btn:hover:not(:disabled) {
            background: #219a52;
        }

        .send-btn:disabled {
            background: #bdc3c7;
            cursor: not-allowed;
        }

        .connection-panel {
            background: #34495e;
            padding: 15px;
            border-radius: 8px;
            margin-bottom: 20px;
            flex-shrink: 0;
        }

        .input-group {
            margin-bottom: 10px;
        }

        .input-group label {
            display: block;
            margin-bottom: 5px;
            font-size: 12px;
            color: #bdc3c7;
        }

        .input-group input {
            width: 100%;
            padding: 8px;
            border: 1px solid #2c3e50;
            border-radius: 4px;
            background: #2c3e50;
            color: white;
            transition: border-color 0.3s;
        }

        .input-group input:focus {
            outline: none;
            border-color: #3498db;
        }

        .btn {
            padding: 8px 15px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 12px;
            width: 100%;
            margin-top: 5px;
            transition: background 0.3s;
        }

        .btn-connect {
            background: #27ae60;
            color: white;
        }

        .btn-connect:hover:not(:disabled) {
            background: #219a52;
        }

        .btn-disconnect {
            background: #e74c3c;
            color: white;
        }

        .btn-disconnect:hover:not(:disabled) {
            background: #c0392b;
        }

        .btn:disabled {
            background: #7f8c8d;
            cursor: not-allowed;
        }

        .typing-indicator {
            padding: 10px 15px;
            color: #7f8c8d;
            font-style: italic;
            font-size: 12px;
        }

        /* 响应式设计 */
        @media (max-width: 768px) {
            .container {
                grid-template-columns: 1fr;
                height: calc(100vh - 40px);
            }

            .sidebar {
                display: none;
            }

            .message {
                max-width: 90%;
            }
        }
    </style>
</head>
<body>
<div class="container">
    <!-- 侧边栏 -->
    <div class="sidebar">
        <div class="sidebar-header">
            <h2>聊天室</h2>
            <div id="userCount">在线: 0人</div>
        </div>

        <div class="connection-panel">
            <div class="input-group">
                <label for="username">用户名</label>
                <input type="text" id="username" placeholder="请输入用户名">
            </div>
            <button id="connectBtn" class="btn btn-connect">加入聊天</button>
            <button id="disconnectBtn" class="btn btn-disconnect" disabled>退出聊天</button>
        </div>

        <div class="user-list" id="userList">
            <div class="empty-state">暂无在线用户</div>
        </div>
    </div>

    <!-- 主内容区 -->
    <div class="main-content">
        <div class="header">
            <h1>群聊</h1>
            <div id="status" class="status disconnected">未连接</div>
        </div>

        <div class="chat-area" id="chatArea">
            <div class="message system">
                <div class="message-content">欢迎来到聊天室！请先设置用户名并连接服务器。</div>
                <div class="timestamp" id="welcomeTime"></div>
            </div>
        </div>

        <div class="input-area">
            <textarea id="messageInput" class="message-input" placeholder="输入消息..." disabled></textarea>
            <button id="sendBtn" class="send-btn" disabled>发送</button>
        </div>
    </div>
</div>

<script>
    class ChatClient {
        constructor() {
            this.socket = null;
            this.isConnected = false;
            this.username = '';
            this.autoScroll = true;
            this.initializeElements();
            this.bindEvents();
            this.generateRandomUsername();
            this.setWelcomeTime();
        }

        initializeElements() {
            this.statusElement = document.getElementById('status');
            this.chatArea = document.getElementById('chatArea');
            this.messageInput = document.getElementById('messageInput');
            this.sendBtn = document.getElementById('sendBtn');
            this.connectBtn = document.getElementById('connectBtn');
            this.disconnectBtn = document.getElementById('disconnectBtn');
            this.usernameInput = document.getElementById('username');
            this.userList = document.getElementById('userList');
            this.userCount = document.getElementById('userCount');
        }

        bindEvents() {
            this.connectBtn.addEventListener('click', () => this.connect());
            this.disconnectBtn.addEventListener('click', () => this.disconnect());
            this.sendBtn.addEventListener('click', () => this.sendMessage());

            this.messageInput.addEventListener('keypress', (e) => {
                if (e.key === 'Enter' && !e.shiftKey) {
                    e.preventDefault();
                    this.sendMessage();
                }
            });

            this.messageInput.addEventListener('input', () => {
                this.adjustTextareaHeight();
            });

            // 监听滚动事件，当用户手动向上滚动时暂停自动滚动
            this.chatArea.addEventListener('scroll', () => {
                const threshold = 100; // 距离底部100px
                const position = this.chatArea.scrollTop + this.chatArea.clientHeight;
                const height = this.chatArea.scrollHeight;

                this.autoScroll = (height - position) <= threshold;
            });
        }

        adjustTextareaHeight() {
            this.messageInput.style.height = 'auto';
            this.messageInput.style.height = Math.min(this.messageInput.scrollHeight, 120) + 'px';
        }

        generateRandomUsername() {
            const adjectives = ['快乐', '聪明', '勇敢', '温柔', '幽默', '神秘', '阳光', '安静'];
            const nouns = ['小猫', '小狗', '熊猫', '老虎', '狮子', '兔子', '狐狸', '小鸟'];
            const adj = adjectives[Math.floor(Math.random() * adjectives.length)];
            const noun = nouns[Math.floor(Math.random() * nouns.length)];
            const randomNum = Math.floor(Math.random() * 1000);
            this.usernameInput.value = `${adj}的${noun}${randomNum}`;
        }

        setWelcomeTime() {
            const welcomeTime = document.getElementById('welcomeTime');
            if (welcomeTime) {
                welcomeTime.textContent = this.formatTime(Date.now());
            }
        }

        connect() {
            const username = this.usernameInput.value.trim();
            if (!username) {
                this.showSystemMessage('请输入用户名');
                return;
            }

            this.username = username;
            const serverUrl = 'ws://localhost:8080/socket-server/websocket';

            console.log('正在连接到:', serverUrl);
            this.showSystemMessage('正在连接服务器...');

            try {
                this.socket = new WebSocket(serverUrl);
                this.socket.onopen = () => this.onOpen();
                this.socket.onmessage = (event) => this.onMessage(event);
                this.socket.onclose = (event) => this.onClose(event);
                this.socket.onerror = (error) => this.onError(error);
            } catch (error) {
                console.error('连接失败:', error);
                this.showSystemMessage('连接失败: ' + error.message);
            }
        }

        onOpen() {
            this.isConnected = true;
            this.updateConnectionStatus();
            this.showSystemMessage('连接服务器成功！正在加入聊天室...');

            // 立即发送JOIN消息
            setTimeout(() => {
                this.sendJoinMessage();
            }, 100);
        }

        sendJoinMessage() {
            if (this.socket && this.socket.readyState === WebSocket.OPEN) {
                const joinMessage = {
                    type: 'JOIN',
                    sender: this.username
                };

                try {
                    this.socket.send(JSON.stringify(joinMessage));
                    this.showSystemMessage('已发送加入请求...');
                } catch (error) {
                    this.showSystemMessage('发送加入消息失败: ' + error.message);
                }
            }
        }

        onMessage(event) {
            console.log('收到消息:', event.data);

            try {
                const message = JSON.parse(event.data);

                // 处理用户列表更新
                if (message.content && message.content.startsWith('[') && message.content.endsWith(']')) {
                    try {
                        const userList = JSON.parse(message.content);
                        if (Array.isArray(userList)) {
                            this.updateUserList(userList);
                            return;
                        }
                    } catch (e) {
                        // 不是用户列表，继续正常处理
                    }
                }

                this.displayMessage(message);
                this.handleMessageType(message);

            } catch (error) {
                console.error('消息解析错误:', error);
                this.displayMessage({
                    type: 'SYSTEM',
                    content: event.data,
                    sender: '系统',
                    timestamp: Date.now()
                });
            }
        }

        /**
         * 更新在线用户列表
         */
        updateUserList(users) {
            const userList = document.getElementById('userList');
            const userCount = document.getElementById('userCount');

            // 更新用户数量
            userCount.textContent = `在线: ${users.length}人`;

            // 清空现有列表
            userList.innerHTML = '';

            if (users.length === 0) {
                userList.innerHTML = '<div class="empty-state">暂无在线用户</div>';
                return;
            }

            // 添加当前用户到列表（如果不在列表中）
            const allUsers = [...users];
            if (!allUsers.includes(this.username) && this.isConnected) {
                allUsers.push(this.username);
            }

            // 创建用户列表项
            allUsers.forEach(user => {
                const userElement = document.createElement('div');
                userElement.className = 'user-item';

                // 标识当前用户
                const isCurrentUser = user === this.username;
                const displayName = isCurrentUser ? `${user} (我)` : user;

                userElement.innerHTML = `
                        <div class="user-avatar">${user.charAt(0)}</div>
                        <div class="user-name">${this.escapeHtml(displayName)}</div>
                        ${isCurrentUser ? '<div class="user-status">● 在线</div>' : ''}
                    `;

                // 高亮当前用户
                if (isCurrentUser) {
                    userElement.style.background = '#2c3e50';
                    userElement.style.borderLeft = '3px solid #27ae60';
                }

                userList.appendChild(userElement);
            });

            console.log('更新用户列表:', allUsers);
        }

        handleMessageType(message) {
            switch (message.type) {
                case 'SYSTEM':
                    if (message.content.includes('加入了聊天室') ||
                        message.content.includes('离开了聊天室')) {
                        // 用户变动，可以请求更新用户列表
                        this.requestUserListUpdate();
                    } else if (message.content.includes('在线用户数')) {
                        // 只更新数量，不更新列表
                        this.updateUserCount(message.content);
                    }
                    break;
                case 'ERROR':
                    this.showSystemMessage('错误: ' + message.content);
                    break;
            }
        }

        /**
         * 请求更新用户列表
         */
        requestUserListUpdate() {
            // 可以发送一个请求来获取最新的用户列表
            // 或者等待服务器自动推送
            console.log('用户变动，等待服务器推送更新...');
        }

        /**
         * 只更新用户数量显示
         */
        updateUserCount(content) {
            const userCount = document.getElementById('userCount');
            userCount.textContent = content.replace('当前在线用户数: ', '在线: ') + '人';
        }

        onClose(event) {
            console.log('连接关闭:', event.code, event.reason);
            this.isConnected = false;
            this.updateConnectionStatus();

            if (event.code === 1000) {
                this.showSystemMessage('连接正常关闭');
            } else {
                this.showSystemMessage(`连接异常关闭 (代码: ${event.code})`);
            }

            // 清空用户列表
            this.updateUserList([]);
        }

        onError(error) {
            console.error('WebSocket错误:', error);
            this.showSystemMessage('连接错误');
        }

        disconnect() {
            if (this.socket) {
                // 发送离开消息
                const leaveMessage = {
                    type: 'LEAVE',
                    sender: this.username
                };

                try {
                    this.socket.send(JSON.stringify(leaveMessage));
                } catch (error) {
                    console.error('发送离开消息失败:', error);
                }

                this.socket.close(1000, '用户主动断开');
                this.socket = null;
            }
            this.isConnected = false;
            this.updateConnectionStatus();
        }

        sendMessage() {
            if (!this.isConnected || !this.socket) {
                this.showSystemMessage('未连接到服务器');
                return;
            }

            const content = this.messageInput.value.trim();
            if (!content) {
                return;
            }

            const message = {
                type: 'TEXT',
                sender: this.username,
                content: content,
                timestamp: Date.now()
            };

            try {
                this.socket.send(JSON.stringify(message));
                this.messageInput.value = '';
                this.messageInput.style.height = '60px';

            } catch (error) {
                this.showSystemMessage('发送消息失败: ' + error.message);
            }
        }

        displayMessage(message) {
            const messageElement = document.createElement('div');

            if (message.type === 'SYSTEM' || message.type === 'ERROR') {
                messageElement.className = 'message system';
                messageElement.innerHTML = `
                        <div class="message-content">${this.escapeHtml(message.content)}</div>
                        <div class="timestamp">${this.formatTime(message.timestamp)}</div>
                    `;
            } else {
                const isOwn = message.sender === this.username;
                messageElement.className = `message ${isOwn ? 'user' : 'other'}`;
                messageElement.innerHTML = `
                        <div class="message-info">${isOwn ? '我' : this.escapeHtml(message.sender)}</div>
                        <div class="message-content">${this.escapeHtml(message.content)}</div>
                        <div class="timestamp">${this.formatTime(message.timestamp)}</div>
                    `;
            }

            this.chatArea.appendChild(messageElement);

            // 自动滚动到底部
            if (this.autoScroll) {
                this.scrollToBottom();
            }
        }

        scrollToBottom() {
            // 使用requestAnimationFrame确保在DOM更新后滚动
            requestAnimationFrame(() => {
                this.chatArea.scrollTop = this.chatArea.scrollHeight;
            });
        }

        showSystemMessage(content) {
            this.displayMessage({
                type: 'SYSTEM',
                content: content,
                timestamp: Date.now()
            });
        }

        updateConnectionStatus() {
            if (this.isConnected) {
                this.statusElement.textContent = '已连接';
                this.statusElement.className = 'status connected';
                this.connectBtn.disabled = true;
                this.disconnectBtn.disabled = false;
                this.messageInput.disabled = false;
                this.sendBtn.disabled = false;
                this.usernameInput.disabled = true;
                this.messageInput.focus();
            } else {
                this.statusElement.textContent = '未连接';
                this.statusElement.className = 'status disconnected';
                this.connectBtn.disabled = false;
                this.disconnectBtn.disabled = true;
                this.messageInput.disabled = true;
                this.sendBtn.disabled = true;
                this.usernameInput.disabled = false;
            }
        }

        formatTime(timestamp) {
            if (!timestamp) return '未知时间';

            try {
                const date = new Date(timestamp);
                if (isNaN(date.getTime())) {
                    return new Date().toLocaleTimeString('zh-CN');
                }
                return date.toLocaleTimeString('zh-CN', {
                    hour: '2-digit',
                    minute: '2-digit',
                    second: '2-digit'
                });
            } catch (error) {
                console.error('时间格式化错误:', error);
                return new Date().toLocaleTimeString('zh-CN');
            }
        }

        escapeHtml(unsafe) {
            if (!unsafe) return '';
            return unsafe
                .replace(/&/g, "&amp;")
                .replace(/</g, "&lt;")
                .replace(/>/g, "&gt;")
                .replace(/"/g, "&quot;")
                .replace(/'/g, "&#039;");
        }
    }

    // 初始化客户端
    document.addEventListener('DOMContentLoaded', () => {
        window.chatClient = new ChatClient();
    });
</script>
</body>
</html>